﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media.Media3D;

namespace Wpf3dTestApp
{
    public static class Extensions3D
    {
        public const double Epsilon = 1E-8;

        public static Point3D Plus(this Point3D point, Point3D other)
        {
            return new Point3D(point.X + other.X, point.Y + other.Y, point.Z + other.Z);
        }

        public static Point3D Minus(this Point3D point, Point3D other)
        {
            return new Point3D(point.X - other.X, point.Y - other.Y, point.Z - other.Z);
        }

        public static Point3D Multiply(this Point3D point, double number)
        {
            return new Point3D(number * point.X, number * point.Y, number * point.Z);
        }

        public static double Length(this Point3D point)
        {
            return Math.Sqrt(point.ScalarProduct(point));
        }

        public static bool IsZero(this Point3D point)
        {
            return point.Length() < Epsilon;
        }

        public static Point3D UnitVector(this Point3D point)
        {
            if (point.IsZero())
            {
                throw new ArgumentException("Cannot make unit vector of point zero!");
            }

            return point.Multiply(1 / point.Length());
        }

        public static Point3D Reverse(this Point3D point)
        {
            return point.Multiply(-1);
        }

        public static double ScalarProduct(this Point3D point, Point3D other)
        {
            return point.X * other.X + point.Y * other.Y + point.Z * other.Z;
        }

        public static Point3D VectorProduct(this Point3D point, Point3D other)
        {
            double a1 = point.X;
            double a2 = point.Y;
            double a3 = point.Z;

            double b1 = other.X;
            double b2 = other.Y;
            double b3 = other.Z;

            return new Point3D(GetDeterminant(a2, a3, b2, b3), -GetDeterminant(a1, a3, b1, b3), GetDeterminant(a1, a2, b1, b2));
        }

        public static Point3D ToPoint(this Vector3D vector)
        {
            return new Point3D(vector.X, vector.Y, vector.Z);
        }

        private static double GetDeterminant(double a11, double a12, double a21, double a22)
        {
            return a11 * a22 - a12 * a21;
        }
    }
}
